import datetime

from .time import Time

_number_of_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

def number_of_days(m):
    assert m >= 1 and m <= 12
    return _number_of_days[m]

def next(schedule, start=None):
    '''Calculate the first time *after* `start` that `schedule` will
    be triggered.

    Args:
      * schedule: The schedule to be checked.
      * start: The time after which `schedule` should be checked. If
          `None`, this defaults to ``datetime.datetime.now()``.

    Returns:
      A ``datetime.datetime`` indicating the first time after `start`
      that `schedule` should be triggered. If there is no time, this
      returns `None`.
    '''
    if start is None:
        start = datetime.datetime.now()

    n = Time(start.year,
             start.month,
             start.day,
             start.hour,
             start.minute + 1)

    while n.year <= max(schedule.years):
        if n.year in schedule.years:
            if next_month(schedule, n):
                return datetime.datetime(year=n.year,
                                         month=n.month,
                                         day=n.day,
                                         hour=n.hour,
                                         minute=n.minute)

        n.year += 1

        n.month = 0
        n.day = 0
        n.hour = 0
        n.minute = 0

def next_month(schedule, n):
    while n.month < 12:
        if n.month in schedule.months:
            if next_day(schedule, n):
                return True

        n.month += 1

        n.day = 0
        n.hour = 0
        n.minute = 0

    return False

def next_day(schedule, n):
    num_days = number_of_days(n.month)
    while n.day < num_days:
        if n.day in schedule.days:
            if next_hour(schedule, n):
                return True

        n.day += 1
        n.hour = 0
        n.minute = 0

    return False

def next_hour(schedule, n):
    while n.hour < 24:
        if n.hour in schedule.hours:
            if next_minute(schedule, n):
                return  True
        
        n.hour += 1
        n.minute = 0

    return False

def next_minute(schedule, n):
    while n.minute < 60:
        if n.minute in schedule.minutes:
            return True

        n.minute += 1

    return False

